package com.junjiao.util.java.sms;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

public class SmsClient {

	private static Logger logger = Logger.getLogger(SmsClient.class);

	public static interface PackType {
		public static final String TEST_BACK = "0000";// 客户端发送的测试包
		public static final String LOGIN_BACK = "0001";// Login回复包
		public static final String DATA_BACK = "0002";// 客户端发送的数据包
		public static final String RECEIVE_BACK = "0003";// 接收情况回复包
		public static final String LOGIN_REQUEST_BACK = "0004";// Login请求包
		public static final String OVERTIME_BACK = "0005";// 连接超时回复包
	}

	public static final String COMPART_TAG = "&";// 数据包不同字段的分隔符

	public static interface ReceiveCode {
		public static final String LOGIN_SUCCESS = "000";// 登陆成功
		public static final String LAWLESS_USER_NAME = "002";// 非法用户名
		public static final String LAWLESS_USER_PASS = "003";// 密码错误
		public static final String RECEIVE_SUCCESS = "001";// 数据包正确，接收成功
		public static final String LAWLESS_FROMAT = "004";// 非法格式数据包
		public static final String LAWLESS_AIM_PHONE = "005";// 非法目标号码
		public static final String LINK_OVERTIME = "006";// 连接超时
		public static final String INFO_TOO_LONG = "007";// 信息内容长度太长
		public static final String LAWLESS_SEND_PHONE = "008";// 非法发送号码
		public static final String LAWLESS_SEND_TIME = "009";// 非法申请发送时间
		public static final String LAWLESS_MSG_TYPE = "010";// 非法短信业务类型
		public static final String USER_NOT_OPEN = "011";// 用户没有开通
		public static final String USER_NOT_LOGIN = "012";// 你还未登录或者会话已过期，请先登录，再发送数据包
		public static final String LAWLESS_LOGIN_FROMAT = "013";// Login数据包格式错误
		public static final String TOO_MANY_REQUESTS = "014";// 请求次数太多
		public static final String SEND_LIMIT = "015";// 短信发送量超过服务器限定的最大值
		public static final String LAWLESS_LOGIN_IP = "016"; // 非法的登录ip
		public static final String TOO_MANY_SAME_MESSAGE = "017"; // 短时间内大量的相同信息和相同目标
		public static final String TOO_MANY_SMS = "018"; // 流量溢出
	}

	public static class ReceiveInfo {
		public static final Map<String, String> map = new HashMap<String, String>();
		static {
			map.put(ReceiveCode.LOGIN_SUCCESS, "登录成功");
			map.put(ReceiveCode.LAWLESS_USER_NAME, "非法用户名");
			map.put(ReceiveCode.LAWLESS_USER_PASS, "密码错误");
			map.put(ReceiveCode.RECEIVE_SUCCESS, "数据包正确，接收成功");
			map.put(ReceiveCode.LAWLESS_FROMAT, "非法格式数据包");
			map.put(ReceiveCode.LAWLESS_AIM_PHONE, "非法目标号码");
			map.put(ReceiveCode.LINK_OVERTIME, "连接超时");
			map.put(ReceiveCode.INFO_TOO_LONG, "信息内容长度太长");
			map.put(ReceiveCode.LAWLESS_SEND_PHONE, "非法发送号码");
			map.put(ReceiveCode.LAWLESS_SEND_TIME, "非法申请发送时间");
			map.put(ReceiveCode.LAWLESS_MSG_TYPE, "非法短信业务类型");
			map.put(ReceiveCode.USER_NOT_OPEN, "用户没有开通");
			map.put(ReceiveCode.USER_NOT_LOGIN, "你还未登录或者会话已过期，请先登录，再发送数据包");
			map.put(ReceiveCode.LAWLESS_LOGIN_FROMAT, "Login数据包格式错误");
			map.put(ReceiveCode.TOO_MANY_REQUESTS, "请求次数太多");
			map.put(ReceiveCode.SEND_LIMIT, "短信发送量超过服务器限定的最大值");
			map.put(ReceiveCode.LAWLESS_LOGIN_IP, "非法的登录ip");
			map.put(ReceiveCode.TOO_MANY_SAME_MESSAGE, "短时间内大量的相同信息和相同目标");
			map.put(ReceiveCode.TOO_MANY_SMS, "流量溢出");
		}
	}

	private String userId;
	private String password;
	private String sequenceId = "0000";
	private String ip;
	private int port;
	private Socket socket;
	private InputStream is;
	private OutputStream os;
	private boolean loginFlag;

	public SmsClient(String ip, int port) {
		this.ip = ip;
		this.port = port;
	}

	public static InetAddress getInetAddressByIp(String ip) {
		InetAddress address = null;
		if (ip != null && !"".equals(ip)) {
			String[] ips = ip.split("\\.");
			int length = ips.length;
			byte[] bs = new byte[length];
			for (int i = 0; i < length; i++) {
				bs[i] = (byte) Integer.parseInt(ips[i]);
			}
			try {
				address = InetAddress.getByAddress(bs);
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}
		}
		return address;
	}

	/**
	 * 取得socket 链接
	 * 
	 * @param address
	 *            互联网协议 (IP) 地址
	 * @param port
	 *            端口号
	 * @return
	 */
	public static Socket getSocketByInetAddress(InetAddress address, int port)
			throws Exception {
		Socket socket = null;
		try {
			socket = new Socket(address, port);
			return socket;
		} catch (Exception e) {
			throw e;
		}
	}

	public boolean connection() {
		try {
			// socket = SocketUtil.getSocketByIp(ip, port);
			InetAddress address = getInetAddressByIp(ip);
			if (address != null) {
				socket = getSocketByInetAddress(address, port);
			}
			is = socket.getInputStream();
			os = socket.getOutputStream();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	public void distroy() {
		try {
			if (is != null)
				is.close();
			if (os != null)
				os.close();
			if (socket != null)
				socket.close();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}

	public boolean login() {
		boolean flag = connection();
		if (flag) {
			try {
				sendLoginData();
				receiveLoginData();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			logger.info("连接不上服务器。。。");
		}
		return loginFlag;
	}

	/**
	 * 发送登录数据包
	 * 
	 * @throws IOException
	 */
	private void sendLoginData() throws IOException {
		// 构建登录
		byte[] tagByte = COMPART_TAG.getBytes();
		byte[] packHeadByte = PackType.LOGIN_REQUEST_BACK.getBytes();
		byte[] userIdByte = userId.getBytes();
		byte[] passwordByte = password.getBytes();
		byte[] sequenceIdByte = sequenceId.getBytes();
		int length = packHeadByte.length;
		length += userIdByte.length;
		length += passwordByte.length;
		length += sequenceIdByte.length;
		length += 4;
		length = length + (length + "").getBytes().length;
		ByteBuffer bb = ByteBuffer.allocate(length);
		bb.put((length + "").getBytes());
		bb.put(tagByte);
		bb.put(packHeadByte);
		bb.put(tagByte);
		bb.put(sequenceIdByte);
		bb.put(tagByte);
		bb.put(userIdByte);
		bb.put(tagByte);
		bb.put(passwordByte);
		// 发送登录数据
		os.write(bb.array());

		// // 发送分包数据
		// os.write((length + "").getBytes());
		// try {
		// Thread.sleep(100);
		// } catch (InterruptedException e) {
		// e.printStackTrace();
		// }
		// os.write(tagByte);
		// os.write(packHeadByte);
		// os.write(tagByte);
		// os.write(sequenceIdByte);
		// os.write(tagByte);
		// os.write(userIdByte);
		// os.write(tagByte);
		// os.write(passwordByte);

		os.flush();

		logger.info("发送登录包：" + new String(bb.array()));
	}

	/**
	 * 接收登录返回数据包
	 * 
	 * @throws IOException
	 */
	private void receiveLoginData() throws IOException {
		// 读取登录返回数据
		byte[] readData = new byte[100];
		is.read(readData);
		String receiveStr = new String(readData).trim();
		logger.info("接收登录返回包 = " + receiveStr);
		// pageLength:[0],packType:[1],sequenceId:[2],result:[3]
		String[] datas = receiveStr.split(COMPART_TAG);

		if (datas.length < 2) {
			logger.info("接收数据包为空或格式错误！");
			return;
		}
		String pageType = datas[1];// 包类型
		// 判断数据包的类型 登录返回包
		if (PackType.LOGIN_BACK.equals(pageType)) {
			if (ReceiveCode.LOGIN_SUCCESS.equals(datas[3])) {
				loginFlag = true;
			} else {
				logger.info("登录失败代码：" + datas[3]);
			}
		}
	}

	/**
	 * 发送短信
	 * 
	 * @param sms
	 * @return
	 */
	public String sendSms(SmsMessage sms) {
		if (loginFlag == false) {
			login();
		}
		if (loginFlag) {
			String smsType = sms.getSmsType();
			if (smsType == null)
				smsType = PackType.DATA_BACK;
			// 发送短信数据包
			byte[] tagByte = COMPART_TAG.getBytes();
			byte[] packHeadByte = smsType.getBytes();
			byte[] sequenceIdByte = sms.getSequenceId().getBytes();
			byte[] targetNumberByte = sms.getTargetNumber().getBytes();
			byte[] sendNumberByte = sms.getSendNumber().getBytes();
			byte[] contentByte = null;
			try {
				contentByte = sms.getContent().getBytes("GBK");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			byte[] createTimeByte = sms.getCreateTime().getBytes();
			int length = packHeadByte.length;
			length += sequenceIdByte.length;
			length += targetNumberByte.length;
			length += sendNumberByte.length;
			length += contentByte.length;
			length += createTimeByte.length;
			length += 6;
			length = length + (length + "").getBytes().length;
			try {
				ByteBuffer bb = ByteBuffer.allocate(length);
				bb.put((length + "").getBytes());
				bb.put(tagByte);
				bb.put(packHeadByte);
				bb.put(tagByte);
				bb.put(sequenceIdByte);
				bb.put(tagByte);
				bb.put(targetNumberByte);
				bb.put(tagByte);
				bb.put(sendNumberByte);
				bb.put(tagByte);
				bb.put(contentByte);
				bb.put(tagByte);
				bb.put(createTimeByte);
				// 发送短信数据
				os.write(bb.array());

				// // 分包发送
				// os.write((length + 1 + "").getBytes());
				// os.write(tagByte);
				// os.write(packHeadByte);
				// try {
				// Thread.sleep(1000);
				// } catch (InterruptedException e) {
				// e.printStackTrace();
				// }
				// os.write(tagByte);
				// os.write(sequenceIdByte);
				// os.write(tagByte);
				// os.write(targetNumberByte);
				// os.write(tagByte);
				// os.write(sendNumberByte);
				// os.write(tagByte);
				// os.write(contentByte);
				// os.write(tagByte);
				// os.write(createTimeByte);
				// // 粘包数据
				// os.write(createTimeByte);

				os.flush();
				logger.info("发送短信包：" + new String(bb.array(), "GBK"));
			} catch (Exception e) {
				e.printStackTrace();
			}
			// 接收发送短信返回数据包
			byte[] readData = new byte[100];
			try {
				is.read(readData);
			} catch (Exception e) {
				e.printStackTrace();
			}
			String receiveStr = new String(readData).trim();
			logger.info("接收短信返回包 = " + receiveStr);
			// pageLength:[0],packType:[1],sequenceId:[2],result:[3]
			String[] datas = receiveStr.split(COMPART_TAG);
			if (datas.length < 2) {
				logger.info("接收数据包为空或格式错误！");
				return null;
			}
			String pageType = datas[1];// 包类型
			String receiveCode = datas[3];// 返回的状态码
			// 判断数据包的类型 短信返回包
			if (PackType.RECEIVE_BACK.equals(pageType)) {
				sms.setReceiveCode(receiveCode);
				if (ReceiveCode.RECEIVE_SUCCESS.equals(datas[3])) {
					sms.setReceiveId(datas[4]);
				} else {
					sms.setReceiveInfo(ReceiveInfo.map.get(receiveCode));
				}
			}
			return receiveStr;
		} else {
			System.out.println("请先登录。。。");
		}
		return null;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public class SmsMessage {
		private String targetNumber;// 目标号码
		private String sendNumber;// 发送号码
		private String sequenceId;
		private String content;// 短信内容
		private String createTime;
		private String smsType; // 短信类型
		private String receiveCode;// 返回的状态码
		private String receiveId;// 返回的smsId
		private String receiveInfo;// 返回状态描述

		public String getTargetNumber() {
			return targetNumber;
		}

		public void setTargetNumber(String targetNumber) {
			this.targetNumber = targetNumber;
		}

		public String getSequenceId() {
			return sequenceId;
		}

		public void setSequenceId(String sequenceId) {
			this.sequenceId = sequenceId;
		}

		public String getContent() {
			return content;
		}

		public void setContent(String content) {
			this.content = content;
		}

		public String getCreateTime() {
			return createTime;
		}

		public void setCreateTime(String createTime) {
			this.createTime = createTime;
		}

		public String getSendNumber() {
			return sendNumber;
		}

		public void setSendNumber(String sendNumber) {
			this.sendNumber = sendNumber;
		}

		public String getSmsType() {
			return smsType;
		}

		public void setSmsType(String smsType) {
			this.smsType = smsType;
		}

		public String getReceiveCode() {
			return receiveCode;
		}

		public void setReceiveCode(String receiveCode) {
			this.receiveCode = receiveCode;
		}

		public String getReceiveId() {
			return receiveId;
		}

		public void setReceiveId(String receiveId) {
			this.receiveId = receiveId;
		}

		public String getReceiveInfo() {
			return receiveInfo;
		}

		public void setReceiveInfo(String receiveInfo) {
			this.receiveInfo = receiveInfo;
		}

	}

	public static void main(String[] args) {
		int sendSize = 1;
		SmsClient client = new SmsClient("116.228.55.215", 3000);

		client.setUserId("WANGMEI");
		client.setPassword("WM_123");
		if (client.login()) {
			for (int i = 0; i < sendSize; i++) {
				SmsMessage sms = client.new SmsMessage();
				// SmsMessage sms = new SmsMessage();
				sms.setSequenceId("1234");
				sms.setContent("恭喜你，中奖了！");
				sms.setTargetNumber("13681864410");
				sms.setSendNumber("118114");
				SimpleDateFormat sdf = new SimpleDateFormat(
						"yyyy-MM-dd HH:mm:ss");
				sms.setCreateTime(sdf.format(new Date()));

				sms.setSmsType(PackType.DATA_BACK);
				String receiveStr = client.sendSms(sms);
				if (receiveStr != null && sms.getReceiveId() != null) {
					logger.info("send ok smsId = " + sms.getReceiveId());
				} else {
					logger.info("send fail errorCode = " + sms.getReceiveCode()
							+ ", errorInfo = " + sms.getReceiveInfo());
				}
			}
		}
		client.distroy();
	}

}
